using System;
using System.Data;
using System.Web;
using System.Collections;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Drawing;
using System.Drawing.Imaging;
using System.Drawing.Drawing2D;

namespace ImageReview
{
    /// <summary>
    /// Used to paste a picture of a set size
    /// </summary>
    public class ImageHandler : IHttpHandler
    {
        public void ProcessRequest( HttpContext context )
        {
            // Extract Query information.
            String imagePath = ( context.Request.QueryString[ "path" ] != null ) ? context.Request.QueryString[ "path" ] : null;
            String imageName = ( context.Request.QueryString[ "file" ] != null ) ? context.Request.QueryString[ "file" ] : null;
            String noThumb = ( context.Request.QueryString[ "noThumb" ] != null ) ? context.Request.QueryString[ "noThumb" ] : null;

            // Map requested path
            String imagepath = String.Empty;
            if( imagePath != null )
                imagepath = imagePath;

            if( imageName != null )
                imagepath = context.Request.MapPath( System.IO.Path.Combine( imagepath, imageName ) );
            else
                imagepath = context.Request.MapPath( context.Request.QueryString[ "noThumb" ] );

            // Determine the thumbnail size. The default is 200.
            int imageSize = 0, imageWidth = 0, imageHeight = 0;
            try { imageSize = Convert.ToInt32( context.Request.QueryString[ "Size" ] ); }
            catch( Exception ) { imageSize = 200; }
            try { imageWidth = Convert.ToInt32( context.Request.QueryString[ "Width" ] ); }
            catch( Exception ) { imageWidth = 0; }
            try { imageHeight = Convert.ToInt32( context.Request.QueryString[ "Height" ] ); }
            catch( Exception ) { imageHeight = 0; }

            // Create a bitmap of the thumbnail
            try { GenerateBitmap( context, imagepath, imageSize, imageWidth, imageHeight ); }
            catch( Exception )
            {
                // Requested image cannot be loaded, try to load the 'NoThumb' image
                if( imageName == null )
                    // Damn, we already tried the NoThumb image. Quitely return...
                    return;

                imagepath = context.Request.MapPath( noThumb );

                // Create a bitmap of the thumbnail
                try { GenerateBitmap( context, imagepath, imageSize, imageWidth, imageHeight ); }

                // Damn!! Quitely return...
                catch( Exception ) { return; }
            } // end catch 
        }

        private void GenerateBitmap( HttpContext context, String imagePath, Int32 imageSize, Int32 imageWidth, Int32 imageHeight )
        {
            //// NOTE 1: So many ways to skin a cat. This comes from MSDN for creating thumbnails only!! Poor quality.
            //Bitmap bitmap = new Bitmap( imagePath );
            //Size newSize = CalculateDimensions( bitmap.Size, imageSize );
            //bitmap = (Bitmap)bitmap.GetThumbnailImage( newSize.Width, newSize.Height, new Image.GetThumbnailImageAbort( ThumbnailCallback ), IntPtr.Zero );

            // NOTE 2: This comes from the PersonalWS starter kit, and is useful for setting images to a specific size, with good quality.
            using( System.Drawing.Image oldImage = new Bitmap( imagePath ) )
            {
                Size newSize = CalculateDimensions( oldImage.Size, imageSize, imageWidth, imageHeight );

                using( Bitmap newImage = new Bitmap( newSize.Width, newSize.Height, PixelFormat.Format24bppRgb ) )
                {
                    using( Graphics canvas = Graphics.FromImage( newImage ) )
                    {
                        canvas.SmoothingMode = ( imageSize <= 200 ) ? SmoothingMode.HighSpeed : SmoothingMode.HighQuality;
                        canvas.InterpolationMode = ( imageSize <= 200 ) ? InterpolationMode.Default : InterpolationMode.HighQualityBicubic;
                        canvas.PixelOffsetMode = ( imageSize <= 200 ) ? PixelOffsetMode.HighSpeed : PixelOffsetMode.HighQuality;
                        canvas.DrawImage( oldImage, new Rectangle( new Point( 0, 0 ), newSize ) );

                        context.Response.ContentType = "image/Jpeg";
                        newImage.Save( context.Response.OutputStream, ImageFormat.Jpeg );
                    }
                }
            }
        }

        private static Size CalculateDimensions( Size oldSize, int targetSize, int targetWidth, int targetHeight )
        {
            Size newSize = new Size( );

            if( targetWidth > 0 && targetHeight > 0 )
            {
                // If both sizes are specified, we never distort the picture, but instead select the most 
                // appropriate size to use.
                if( oldSize.Height > oldSize.Width )
                {
                    newSize.Width = (int)( oldSize.Width * ( (float)targetHeight / (float)oldSize.Height ) );
                    if( newSize.Width > targetWidth )
                    {
                        newSize.Width = targetWidth;
                        newSize.Height = (int)( oldSize.Height * ( (float)targetWidth / (float)oldSize.Width ) );
                    }
                    else
                        newSize.Height = targetHeight;
                }
                else
                {
                    newSize.Height = (int)( oldSize.Height * ( (float)targetWidth / (float)oldSize.Width ) );
                    if( newSize.Height > targetHeight )
                    {
                        newSize.Width = (int)( oldSize.Width * ( (float)targetHeight / (float)oldSize.Height ) );
                        newSize.Height = targetHeight;
                    }
                    else
                        newSize.Width = targetWidth;
                }
            }
            else if( ( ( oldSize.Height > oldSize.Width ) || ( targetHeight > 0 ) ) && ( targetWidth <= 0 ) )
            {
                int size = ( targetHeight > 0 ) ? targetHeight : targetSize;

                newSize.Width = (int)( oldSize.Width * ( (float)size / (float)oldSize.Height ) );
                newSize.Height = size;
            }
            else
            {
                int size = ( targetWidth > 0 ) ? targetWidth : targetSize;

                newSize.Width = size;
                newSize.Height = (int)( oldSize.Height * ( (float)size / (float)oldSize.Width ) );
            }
            return newSize;
        }

        public bool ThumbnailCallback( ) { return false; }

        public bool IsReusable
        {
            get { return false; }
        }
    }
}
